package redecolaborativa.server.gerentes;



import java.io.Serializable;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import redecolaborativa.server.enums.BaseDePesquisa;
import redecolaborativa.server.excecoes.*;
import redecolaborativa.server.objetos.Item;
import redecolaborativa.server.sistema.Usuario;
import redecolaborativa.server.util.*;


public class GerenciadorDeItens implements Serializable {
	private static final long serialVersionUID = 1L;
	private List<Item> itens, notificacoesDeItemLivre;
	
	public GerenciadorDeItens() {
		itens =  new LinkedList<Item>();
		notificacoesDeItemLivre = new LinkedList<Item>();
	}
	
	/**
	 * Retorna a copia da lista de itens do usuario.
	 * @return A copia da lista de itens do usuario.
	 */
	public List<Item> getItens(){
		return new LinkedList<Item>(itens);
	}
	
	/**
	 * Recupera uma copia da lista de notificacoes de itens livres.
	 * @return Uma copia lista de notificacoes de itens livres
	 */
	public List<Item> getNotificacoesDeItemLivre() {
		return new LinkedList<Item>(notificacoesDeItemLivre);
	}
	
	/**
	 * Adiciona um item a lista de itens do Usuario.
	 * @param Item a ser adicionado
	 * @return True caso o item for adicionado ou False caso o item nao tiver sido adicionado
	 * @throws InterruptedException 
	 * @throws DonoInvalidoException 
	 * @throws DescricaoInvalidaException 
	 * @throws CategoriaInvalidaException 
	 * @throws NomeInvalidoException 
	 */
	public void adiciona(String nome, List<String> categorias, String descricao, Usuario dono) throws InterruptedException, NomeInvalidoException, CategoriaInvalidaException, DescricaoInvalidaException, DonoInvalidoException {
		Thread.sleep(1);
		Item item = new Item(nome, categorias, descricao, dono);
		if (!itens.contains(item)) {
			itens.add(item);
			String atividade = String.format("%s cadastrou %s", item.getDono().getNome(), item.getNome());
			dono.getHistoricoDeAtividades().adicionaAtividade(atividade, new GregorianCalendar());
		}
	}
	
	/**
	 * Remove um item da lista de itens do usuario.
	 * @param Item a ser removido
	 * @return True caso o item for removido ou false caso o item nao for removido
	 * @throws ItemInvalidoException 
	 * @throws ItemIndisponivelException 
	 */
	public void remove(Item item) throws ItemInvalidoException, ItemIndisponivelException {
		if (!itens.contains(item)) {
			throw new ItemInvalidoException("Item inexistente");
		} if (!item.estaDisponivel()) {
			throw new ItemIndisponivelException("O usuário não pode apagar este item enquanto estiver emprestado");
		} 
		itens.remove(item);
	}
	
	/**
	 * Metodo que registra o interesse em um item
	 * @param item Item ao qual o usuario tem interesse
	 * @param interessado Usuario interessado pelo item
	 * @throws Exception
	 * @throws PermissaoNegadaException
	 * @throws InterruptedException
	 * @throws DonoInvalidoException
	 */
	public void registraInteresse(Item item, Usuario interessado) throws Exception, PermissaoNegadaException, InterruptedException, DonoInvalidoException {
		Thread.sleep(1);
		if(item.getDono().equals(interessado)) {
			throw new DonoInvalidoException("O usuário não pode registrar interesse no próprio item");
		} if(!item.getDono().gerenteDeAmigos().contem(interessado)) {
			throw new PermissaoNegadaException("O usuário não tem permissão para registrar interesse neste item");
		} if(item.estaDisponivel()) {
			throw new Exception("Esse item esta disponivel!");
		} 
		item.adicionaInteressado(interessado);
		String atividade = String.format("%s tem interesse pelo item %s de %s", interessado.getNome(), item.getNome(), item.getDono().getNome());
		interessado.getHistoricoDeAtividades().adicionaAtividade(atividade, new GregorianCalendar());
	}
	
	/**
	 * Adiciona um item na lista de notificacoes de item livre
	 * @param item Item que esta livre
	 */
	public void recebeNotificacaoDeItemLivre(Item item) {
		notificacoesDeItemLivre.add(item);
	}
	
	/**
	 * Metodo que oferece um item a um usuario que fez um pedido
	 * @param nomeUsuario Nome do usuario que fez o pedido
	 * @param nomeItem Nome do item que quer oferecer
	 * @throws DescricaoInvalidaException 
	 * @throws AssuntoInvalidoException 
	 * @throws TipoDeMensagemInvalido 
	 * @throws ItemInvalidoException 
	 * @throws Exception 
	 */
	public Item oferecerItem(Usuario usuario, String nomeItem) throws NomeInvalidoException, ItemInvalidoException, TipoDeMensagemInvalido, AssuntoInvalidoException, DescricaoInvalidaException{
		if (nomeItem.trim().isEmpty()) {
			throw new NomeInvalidoException("Nome inválido");
		} if (pesquisaItemPorNome(nomeItem) != null) {
			return pesquisaItemPorNome(nomeItem);
		} 
		return null;
	}
	
	/**
	 * Metodo que pesquisa por itens.
	 * @param palavraChave da pesquisa
	 * @return Lista com os resultados da pesquisa
	 * @throws AtributoInvalidoException 
	 * @throws TipoInvalidoException 
	 */
	public String pesquisaItens(Usuario pesquisador, String palavraChave, String atributo, String criterio, String tipoOrdenacao) throws AtributoInvalidoException, TipoInvalidoException {
		List<Item> pesquisa = new LinkedList<Item>();
		Iterator<Usuario> itUsuario = pesquisador.gerenteDeAmigos().getAmigos().iterator();
		while (itUsuario.hasNext()){
			Usuario usuario = itUsuario.next();
			Iterator<Item> itItem = usuario.gerenteDeItens().itens.iterator();
			while (itItem.hasNext()) {
				Item item = itItem.next();
				if (VerificadorDeOcorrencia.ocorre(item, palavraChave, atributo)) {
					pesquisa.add(item);
				}
			}
		}
		if (criterio.equalsIgnoreCase(BaseDePesquisa.DATACRIACAO.name())) {
			pesquisa = Util.ordenaPesquisaPorData(pesquisa, tipoOrdenacao);
		} else if (criterio.equalsIgnoreCase(BaseDePesquisa.REPUTACAO.name())) {
			pesquisa = Util.ordenaPesquisaPorReputacao(pesquisa, tipoOrdenacao);
		} 
		return Visualizador.imprimePesquisaItem(pesquisa);
	}
	
	/**
	 * Pesquisa um item na biblioteca a partir de seu id.
	 * @param idItem ID a ser procurado.
	 * @return O Item com o id referente, null caso contrario.
	 * @throws ItemInvalidoException Caso o id do item seja nulo ou vazio.
	 */
	public Item pesquisaItemPorID(String idItem) throws ItemInvalidoException {
		if (idItem == null || idItem.trim().equals(""))	{
			throw new ItemInvalidoException("Identificador do item é inválido");
		} 
		Iterator<Item> it = itens.iterator();
		while (it.hasNext()){
			Item item = it.next();
			if (String.valueOf(item.getID()).equals(idItem)){
				return item;
			}
		}
		return null;
	}
	
	/**
	 * Pesquisa um item na biblioteca a partir de seu nome.
	 * @param nomeItem Nome do item a ser procurado.
	 * @return O item com o referente nome.
	 * @throws ItemInvalidoException Caso o nome do item seja nulo ou vazio.
	 */
	public Item pesquisaItemPorNome(String nomeItem) throws ItemInvalidoException {
		if (nomeItem == null || nomeItem.trim().equals(""))	{
			throw new ItemInvalidoException("Nome do item é inválido");
		} 
		Iterator<Item> it = itens.iterator();
		while (it.hasNext()) {
			Item item =  it.next();
			if (item.getNome().equals(nomeItem)) {
				return item;
			}
		} 
		return null;
	}	
}